/**
 * Copyright 2008 Mathias Doenitz, http://lis.to/
 *
 * This file is part of the lis.to java desktop client. The lis.to java desktop client is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * The lis.to java desktop client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with the lis.to java desktop client.
 * If not, see http://www.gnu.org/licenses/
 */

package listo.client.viewlists;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import listo.client.ImageProvider;
import listo.utils.swing.SwingUtils;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.geom.Rectangle2D;

@Singleton
public class ViewListRenderer extends JPanel implements ListCellRenderer {

    private static final Border NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
    private static final int ICON_TEXT_GAP = 4;
    private static final int COUNT_PADDING = 4;
    private static final int X_PADDING = 3;

    private final ImageProvider imageProvider;

    private boolean initialized;
    private Icon icon;
    private String text;
    private Font font;
    private Font boldFont;
    private int levelIndent;
    private int rowHeight;
    private int textBaseline;
    private int level;
    private int taskCount;
    private boolean bold;

    private Color colorCellBackground;
    private Color colorCellForeground;
    private Color colorFocusedCellBackground;
    private Color colorFocusedCellForeground;
    private Color colorSelectedCellBackground;
    private Color colorSelectedCellForeground;
    private Color colorDropCellBackground;
    private Color colorDropCellForeground;
    private Color colorTaskCountBackground;
    private Color colorTaskCountForeground;
    private int iconX;
    private int iconY;
    private int labelX;

    @Inject
    public ViewListRenderer(ImageProvider imageProvider) {
        this.imageProvider = imageProvider;
    }

    private void initialize(JList list) {
        setOpaque(true);
        font = UIManager.getFont("List.font");
        boldFont = font.deriveFont(Font.BOLD);

        int fontSize = font.getSize();
        rowHeight = (int) (fontSize * 1.8);
        levelIndent = (int) (fontSize * 1.5);
        textBaseline = (int) (fontSize * 1.3);

        colorCellBackground = list.getBackground();
        colorCellForeground = list.getForeground();
        colorFocusedCellBackground = list.getSelectionBackground();
        colorFocusedCellForeground = list.getSelectionForeground();
        colorSelectedCellBackground = SwingUtils.setAlpha(colorFocusedCellBackground, 128);
        colorSelectedCellForeground = list.getSelectionForeground();
        colorDropCellBackground = UIManager.getColor("List.dropCellBackground");
        colorDropCellForeground = UIManager.getColor("List.dropCellForeground");
        if (colorDropCellBackground == null) colorDropCellBackground = colorFocusedCellBackground;
        if (colorDropCellForeground == null) colorDropCellForeground = colorFocusedCellForeground;

        initialized = true;
    }

    public void setIcon(String filename) {
        icon = filename != null ? imageProvider.getIcon(filename) : null;
    }

    public void setText(String text) {
        this.text = text;
    }

    public void setTaskCount(int count) {
        taskCount = count;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public void setBold(boolean bold) {
        this.bold = bold;
    }

    public Dimension getPreferredSize() {
        Dimension dim = super.getPreferredSize();
        dim.setSize(dim.getWidth(), rowHeight);
        return dim;
    }

    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                                                  boolean cellHasFocus) {
        if (!initialized) initialize(list);

        JList.DropLocation dropLocation = list.getDropLocation();
        boolean isDrop = (dropLocation != null && !dropLocation.isInsert() && dropLocation.getIndex() == index);

        if (isDrop) {
            setBackground(colorDropCellBackground);
            setForeground(colorDropCellForeground);
            colorTaskCountBackground = SystemColor.controlShadow;
            colorTaskCountForeground = SystemColor.controlLtHighlight;
        } else if (cellHasFocus) {
            setBackground(colorFocusedCellBackground);
            setForeground(colorFocusedCellForeground);
            colorTaskCountBackground = colorFocusedCellForeground;
            colorTaskCountForeground = colorFocusedCellBackground;
        } else if (isSelected) {
            setBackground(colorSelectedCellBackground);
            setForeground(colorSelectedCellForeground);
            colorTaskCountBackground = colorSelectedCellForeground;
            colorTaskCountForeground = colorSelectedCellBackground;
        } else {
            setBackground(colorCellBackground);
            setForeground(colorCellForeground);
            colorTaskCountBackground = SystemColor.controlShadow;
            colorTaskCountForeground = SystemColor.controlLtHighlight;
        }

        Border border = null;
        if (cellHasFocus) {
            if (isSelected || isDrop) border = UIManager.getBorder("List.focusSelectedCellHighlightBorder");
            if (border == null) border = UIManager.getBorder("List.focusCellHighlightBorder");
        } else {
            border = NO_FOCUS_BORDER;
        }
        setBorder(border);

        View view = (View) value;
        view.render(this, isSelected, cellHasFocus, isDrop);

        layoutComponents();

        return this;
    }

    private void layoutComponents() {
        iconX = X_PADDING + Math.max(0, level - 1) * levelIndent;
        iconY = icon != null ? (rowHeight - icon.getIconHeight() + 1) / 2 : 0;

        labelX = iconX + (icon != null ? icon.getIconWidth() : 0) + ICON_TEXT_GAP;
    }

    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;

        // cell background
        super.paintComponent(g2);

        // icon
        if (icon != null) icon.paintIcon(this, g2, iconX, iconY);

        // label
        g2.setRenderingHints(
                new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB));
        g2.setFont(bold ? boldFont : font);
        g2.drawString(text != null ? text : "", labelX, textBaseline);

        // tash count
        if (taskCount > 0) {
            // task count box
            g2.setFont(boldFont);
            String count = Integer.toString(taskCount);
            Rectangle2D textBounds = g2.getFontMetrics().getStringBounds(count, g2);
            int countBoxX = (int) (getWidth() - textBounds.getMaxX() - 2 * COUNT_PADDING - X_PADDING);
            g2.setRenderingHints(
                    new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
            g2.setColor(colorTaskCountBackground);
            g2.fillRoundRect(countBoxX, 3, (int) (textBounds.getMaxX() + 2 * COUNT_PADDING), rowHeight - 5,
                    rowHeight - 5, rowHeight - 5);

            // task count number text
            int countTextX = countBoxX + COUNT_PADDING;
            g2.setColor(colorTaskCountForeground);
            g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING,
                    RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB));
            g2.drawString(count, countTextX, textBaseline);
        }
    }

    /**
     * ************************************************
     * overridden for performance reasons
     * *************************************************
     */

    public void validate() {
    }

    public void invalidate() {
    }

    public void repaint() {
    }

    public void revalidate() {
    }

    public void repaint(long tm, int x, int y, int width, int height) {
    }

    public void repaint(Rectangle r) {
    }

    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
    }

    public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {
    }

    public void firePropertyChange(String propertyName, char oldValue, char newValue) {
    }

    public void firePropertyChange(String propertyName, short oldValue, short newValue) {
    }

    public void firePropertyChange(String propertyName, int oldValue, int newValue) {
    }

    public void firePropertyChange(String propertyName, long oldValue, long newValue) {
    }

    public void firePropertyChange(String propertyName, float oldValue, float newValue) {
    }

    public void firePropertyChange(String propertyName, double oldValue, double newValue) {
    }

    public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
    }

}
